package it.mauriziobasile.sincrodir.logica;

import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

import it.mauriziobasile.sincrodir.eccezioni.DirNullEcc;
import it.mauriziobasile.sincrodir.eccezioni.VersoNonImpostatoEcc;
import it.mauriziobasile.sincrodir.entita.Directory;
import it.mauriziobasile.sincrodir.entita.File;
import it.mauriziobasile.sincrodir.entita.Filtro;

public class Sincronizzatore {

    private ArrayList<File>[] differenze;

    private ArrayList<Directory>[] differenzeD;

    private Filtro filtro;

    private Directory radice[];

    public static final int DA2A1 = 1;

    public static final int DA1A2 = 2;

    public static final int COMPLETO = 3;

    private int verso;

    public Sincronizzatore(){
        this(null,null,-1);
    }
    
    public void setDir(Directory dir,int quale){
        if (quale==1)
            radice[0]=dir;
        if (quale==2)
            radice[1]=dir;
    }
    
    
    public Sincronizzatore(Directory dir1, Directory dir2, int verso) {
        this.verso = verso;
        radice = new Directory[2];
        radice[0] = dir1;
        radice[1] = dir2;
        inizializzaDifferenze();
        filtro = null;
    }

    @SuppressWarnings("unchecked")
    private void inizializzaDifferenze() {
        differenze = new ArrayList[2];
        differenzeD = new ArrayList[2];
        for (int i = 0; i < 2; i++) {
            differenze[i] = new ArrayList<File>();
            differenzeD[i] = new ArrayList<Directory>();
        }
    }

    public void setVerso(int verso) {
        this.verso = verso;
    }
    
    public int getVerso() {
        return verso;
    }
    
    public void mostraDifferenze() {
        System.out.println("Differenze 2->1: ");
        for (File file : differenze[0]) {
            System.out.println(file.getAbsolutePath());
        }
        System.out.println("Dirs");
        for (Directory file : differenzeD[0]) {
            System.out.println(file.getAbsolutePath());
        }

        System.out.println("Differenze 1->2 ");

        for (File file : differenze[1]) {
            System.out.println(file.getAbsolutePath());
        }
        System.out.println("Dir");
        for (Directory file : differenzeD[1]) {
            System.out.println(file.getAbsolutePath());
        }
        System.out.println("Differenze 2->1: " + differenze[0].size() + " files e " + differenzeD[0].size() + " direcrories.");
        System.out.println("Differenze 1->2: " + differenze[1].size() + " files e " + differenzeD[1].size() + " direcrories.");
    }

    public void vai(boolean simula) throws VersoNonImpostatoEcc,DirNullEcc {
        inizializzaDifferenze();
        if (verso<0)
            throw new VersoNonImpostatoEcc("Verso non impostato");
        if (radice[0]==null || radice[1]==null)
            throw new DirNullEcc("Directory radice non impostate");
        if ((verso & DA1A2) == DA1A2)
            controllaDifferenze(radice[0], radice[1], 2);
        if ((verso & DA2A1) == DA2A1)
            controllaDifferenze(radice[1], radice[0], 1);

        if (!simula)
            sincronizza();
    }

    private void appiattisci(Directory dir, int verso) {
        for (File file : dir.getFileFigli()) {
            if (filtro == null || filtro.devePassare(file))
                differenze[verso - 1].add(file);
        }
        for (Directory dird : dir.getDirFigli()) {
            differenzeD[verso - 1].add(dird);
            appiattisci(dird, verso);
        }

    }

    private void controllaDifferenze(Directory dir1, Directory dir2, int verso) {
        if (dir1 != null && dir2 != null) {
            for (File file : dir1.getFileFigli()) {
                if (!dir2.getFileFigli().contains(file)) {
                    if (filtro == null || filtro.devePassare(file))
                        differenze[verso - 1].add(file);
                }
            }

            for (Directory dir : dir1.getDirFigli()) {
                int idx = dir2.getDirFigli().indexOf(dir);
                if (idx >= 0) {
                    controllaDifferenze(dir, dir2.getDirFigli().get(idx), verso);
                } else {
                    differenzeD[verso - 1].add(dir);
                    controllaDifferenze(dir, null, verso);
                }
            }
        } else {
            if (dir1 == null)
                appiattisci(dir2, verso);
            if (dir2 == null)
                appiattisci(dir1, verso);
        }
    }

    public void sincronizza() {
        System.out.println("Inizio a sincronizzare ...");
        for (int i = 0; i < 2; i++) {
            for (Directory dir : differenzeD[i]) {
                String nuovaDir = dir.getAbsolutePath().replace(radice[1 - i].getAbsolutePath(), radice[i].getAbsolutePath());
                System.out.print("creo dir " + nuovaDir + "..");
                if (FileSystem.creaDirectory(new Directory(nuovaDir,false)))
                    System.out.println("fatto!");

            }
            for (File file : differenze[i]) {
                String nuovoFile = file.getAbsolutePath().replace(radice[1 - i].getAbsolutePath(), radice[i].getAbsolutePath());
                ;
                System.out.print("creo file " + nuovoFile + "..");
                try {
                    FileSystem.copia(file, new File(nuovoFile));
                } catch (IOException e) {
                    Logger.getAnonymousLogger().log(Level.SEVERE, e.getMessage());
                }
            }
        }
    }

    public void setFiltro(Filtro filtro) {
        this.filtro = filtro;
    }

    public Filtro getFiltro() {
        return filtro;
    }
    
    public int getDifferenzeFile(int dd){
        int didx=dd-1;
        if (didx<0)
            didx=0;
        if(didx>differenze.length)
            didx=differenze.length-1;
        return differenze[didx].size();
    }
 
    public int getDifferenzeDir(int dd){
        int didx=dd-1;
        if (didx<0)
            didx=0;
        if(didx>differenzeD.length)
            didx=differenzeD.length-1;
        return differenze[didx].size();
    }
 
}
